In [1]:
%pip install zipline-reloaded
%pip install quandl
%pip install pyfolio-reloaded
Requirement already satisfied: zipline-reloaded in c:\aj_msds\.venv\lib\site-packages (3.1.1) Requirement already satisfied: numpy>=1.26.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.3.3) Requirement already satisfied: pandas<3.0,>=1.3.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.3.3) Requirement already satisfied: alembic>=0.7.7 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.17.1) Requirement already satisfied: bcolz-zipline>=1.2.6 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.13.0) Requirement already satisfied: bottleneck>=1.0.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.6.0) Requirement already satisfied: click>=4.0.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (8.3.0) Requirement already satisfied: empyrical-reloaded>=0.5.7 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (0.5.12) Requirement already satisfied: h5py>=2.7.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.15.1) Requirement already satisfied: intervaltree>=2.1.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.1.0) Requirement already satisfied: iso3166>=2.1.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.1.1) Requirement already satisfied: iso4217>=1.6.20180829 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.14.20250512) Requirement already satisfied: lru-dict>=1.1.4 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.3.0) Requirement already satisfied: multipledispatch>=0.6.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.0.0) Requirement already satisfied: networkx>=2.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.5) Requirement already satisfied: numexpr>=2.6.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.14.1) Requirement already satisfied: patsy>=0.4.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.0.2) Requirement already satisfied: python-dateutil>=2.4.2 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.9.0.post0) Requirement already satisfied: pytz>=2018.5 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2025.2) Requirement already satisfied: requests>=2.9.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.32.5) Requirement already satisfied: scipy>=0.17.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.16.2) Requirement already satisfied: six>=1.10.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.17.0) Requirement already satisfied: sqlalchemy>=2 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.0.44) Requirement already satisfied: statsmodels>=0.6.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (0.14.5) Requirement already satisfied: tables>=3.4.3 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.10.2) Requirement already satisfied: toolz>=0.8.2 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.1.0) Requirement already satisfied: exchange-calendars>=4.2.4 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (4.11.2) Requirement already satisfied: tzdata>=2022.7 in c:\aj_msds\.venv\lib\site-packages (from pandas<3.0,>=1.3.0->zipline-reloaded) (2025.2) Requirement already satisfied: Mako in c:\aj_msds\.venv\lib\site-packages (from alembic>=0.7.7->zipline-reloaded) (1.3.10) Requirement already satisfied: typing-extensions>=4.12 in c:\aj_msds\.venv\lib\site-packages (from alembic>=0.7.7->zipline-reloaded) (4.15.0) Requirement already satisfied: packaging in c:\aj_msds\.venv\lib\site-packages (from bcolz-zipline>=1.2.6->zipline-reloaded) (25.0) Requirement already satisfied: colorama in c:\aj_msds\.venv\lib\site-packages (from click>=4.0.0->zipline-reloaded) (0.4.6) Requirement already satisfied: peewee<3.17.4 in c:\aj_msds\.venv\lib\site-packages (from empyrical-reloaded>=0.5.7->zipline-reloaded) (3.17.3) Requirement already satisfied: pyluach>=2.3.0 in c:\aj_msds\.venv\lib\site-packages (from exchange-calendars>=4.2.4->zipline-reloaded) (2.3.0) Requirement already satisfied: korean_lunar_calendar>=0.3.1 in c:\aj_msds\.venv\lib\site-packages (from exchange-calendars>=4.2.4->zipline-reloaded) (0.3.1) Requirement already satisfied: sortedcontainers<3.0,>=2.0 in c:\aj_msds\.venv\lib\site-packages (from intervaltree>=2.1.0->zipline-reloaded) (2.4.0) Requirement already satisfied: charset_normalizer<4,>=2 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (3.4.3) Requirement already satisfied: idna<4,>=2.5 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (3.10) Requirement already satisfied: urllib3<3,>=1.21.1 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (2.5.0) Requirement already satisfied: certifi>=2017.4.17 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (2025.8.3) Requirement already satisfied: greenlet>=1 in c:\aj_msds\.venv\lib\site-packages (from sqlalchemy>=2->zipline-reloaded) (3.2.4) Requirement already satisfied: py-cpuinfo in c:\aj_msds\.venv\lib\site-packages (from tables>=3.4.3->zipline-reloaded) (9.0.0) Requirement already satisfied: blosc2>=2.3.0 in c:\aj_msds\.venv\lib\site-packages (from tables>=3.4.3->zipline-reloaded) (3.11.0) Requirement already satisfied: ndindex in c:\aj_msds\.venv\lib\site-packages (from blosc2>=2.3.0->tables>=3.4.3->zipline-reloaded) (1.10.0) Requirement already satisfied: msgpack in c:\aj_msds\.venv\lib\site-packages (from blosc2>=2.3.0->tables>=3.4.3->zipline-reloaded) (1.1.2) Requirement already satisfied: platformdirs in c:\aj_msds\.venv\lib\site-packages (from blosc2>=2.3.0->tables>=3.4.3->zipline-reloaded) (4.4.0) Requirement already satisfied: MarkupSafe>=0.9.2 in c:\aj_msds\.venv\lib\site-packages (from Mako->alembic>=0.7.7->zipline-reloaded) (3.0.3) Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 25.2 -> 25.3 [notice] To update, run: python.exe -m pip install --upgrade pip
Requirement already satisfied: quandl in c:\aj_msds\.venv\lib\site-packages (3.7.0) Requirement already satisfied: pandas>=0.14 in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.3.3) Requirement already satisfied: numpy>=1.8 in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.3.3) Requirement already satisfied: requests>=2.7.0 in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.32.5) Requirement already satisfied: inflection>=0.3.1 in c:\aj_msds\.venv\lib\site-packages (from quandl) (0.5.1) Requirement already satisfied: python-dateutil in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.9.0.post0) Requirement already satisfied: six in c:\aj_msds\.venv\lib\site-packages (from quandl) (1.17.0) Requirement already satisfied: more-itertools in c:\aj_msds\.venv\lib\site-packages (from quandl) (10.8.0) Requirement already satisfied: pytz>=2020.1 in c:\aj_msds\.venv\lib\site-packages (from pandas>=0.14->quandl) (2025.2) Requirement already satisfied: tzdata>=2022.7 in c:\aj_msds\.venv\lib\site-packages (from pandas>=0.14->quandl) (2025.2) Requirement already satisfied: charset_normalizer<4,>=2 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (3.4.3) Requirement already satisfied: idna<4,>=2.5 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (3.10) Requirement already satisfied: urllib3<3,>=1.21.1 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (2.5.0) Requirement already satisfied: certifi>=2017.4.17 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (2025.8.3) Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 25.2 -> 25.3 [notice] To update, run: python.exe -m pip install --upgrade pip
Requirement already satisfied: pyfolio-reloaded in c:\aj_msds\.venv\lib\site-packages (0.9.9) Requirement already satisfied: numpy>=1.26.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (2.3.3) Requirement already satisfied: pandas<3.0,>=1.5.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (2.3.3) Requirement already satisfied: ipython>=3.2.3 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (9.6.0) Requirement already satisfied: matplotlib>=1.4.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (3.10.6) Requirement already satisfied: pytz>=2014.10 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (2025.2) Requirement already satisfied: scipy>=0.14.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (1.16.2) Requirement already satisfied: scikit-learn>=0.16.1 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (1.7.2) Requirement already satisfied: seaborn>=0.7.1 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (0.13.2) Requirement already satisfied: empyrical-reloaded>=0.5.9 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (0.5.12) Requirement already satisfied: python-dateutil>=2.8.2 in c:\aj_msds\.venv\lib\site-packages (from pandas<3.0,>=1.5.0->pyfolio-reloaded) (2.9.0.post0) Requirement already satisfied: tzdata>=2022.7 in c:\aj_msds\.venv\lib\site-packages (from pandas<3.0,>=1.5.0->pyfolio-reloaded) (2025.2) Requirement already satisfied: bottleneck>=1.3.0 in c:\aj_msds\.venv\lib\site-packages (from empyrical-reloaded>=0.5.9->pyfolio-reloaded) (1.6.0) Requirement already satisfied: peewee<3.17.4 in c:\aj_msds\.venv\lib\site-packages (from empyrical-reloaded>=0.5.9->pyfolio-reloaded) (3.17.3) Requirement already satisfied: colorama in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.4.6) Requirement already satisfied: decorator in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (5.2.1) Requirement already satisfied: ipython-pygments-lexers in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (1.1.1) Requirement already satisfied: jedi>=0.16 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.19.2) Requirement already satisfied: matplotlib-inline in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.1.7) Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (3.0.52) Requirement already satisfied: pygments>=2.4.0 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (2.19.2) Requirement already satisfied: stack_data in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.6.3) Requirement already satisfied: traitlets>=5.13.0 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (5.14.3) Requirement already satisfied: wcwidth in c:\aj_msds\.venv\lib\site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=3.2.3->pyfolio-reloaded) (0.2.14) Requirement already satisfied: parso<0.9.0,>=0.8.4 in c:\aj_msds\.venv\lib\site-packages (from jedi>=0.16->ipython>=3.2.3->pyfolio-reloaded) (0.8.5) Requirement already satisfied: contourpy>=1.0.1 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (1.3.3) Requirement already satisfied: cycler>=0.10 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (4.60.1) Requirement already satisfied: kiwisolver>=1.3.1 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (1.4.9) Requirement already satisfied: packaging>=20.0 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (25.0) Requirement already satisfied: pillow>=8 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (11.3.0) Requirement already satisfied: pyparsing>=2.3.1 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (3.2.5) Requirement already satisfied: six>=1.5 in c:\aj_msds\.venv\lib\site-packages (from python-dateutil>=2.8.2->pandas<3.0,>=1.5.0->pyfolio-reloaded) (1.17.0) Requirement already satisfied: joblib>=1.2.0 in c:\aj_msds\.venv\lib\site-packages (from scikit-learn>=0.16.1->pyfolio-reloaded) (1.5.2) Requirement already satisfied: threadpoolctl>=3.1.0 in c:\aj_msds\.venv\lib\site-packages (from scikit-learn>=0.16.1->pyfolio-reloaded) (3.6.0) Requirement already satisfied: executing>=1.2.0 in c:\aj_msds\.venv\lib\site-packages (from stack_data->ipython>=3.2.3->pyfolio-reloaded) (2.2.1) Requirement already satisfied: asttokens>=2.1.0 in c:\aj_msds\.venv\lib\site-packages (from stack_data->ipython>=3.2.3->pyfolio-reloaded) (3.0.0) Requirement already satisfied: pure-eval in c:\aj_msds\.venv\lib\site-packages (from stack_data->ipython>=3.2.3->pyfolio-reloaded) (0.2.3) Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 25.2 -> 25.3 [notice] To update, run: python.exe -m pip install --upgrade pip
In [42]:
from zipline import run_algorithm
from zipline.api import (
attach_pipeline,
calendars,
pipeline_output,
date_rules,
time_rules,
set_commission,
set_slippage,
order_target_percent,
get_open_orders,
schedule_function
)
from datetime import datetime
import pytz
import pyfolio as pf
import matplotlib.pyplot as plt
import quandl
import pandas as pd
import zipline
In [ ]:
import os
quandl_api_key = 'API_KEY_HERE'
quandl.ApiConfig.api_key = quandl_api_key
# Set environment variable for Quandl
os.environ['QUANDL_API_KEY'] = 'API_KEY_HERE'
In [4]:
!zipline ingest -b quandl
Downloading WIKI Prices table from Quandl Merging daily equity files:
[2025-11-02T17:31:05-0600-INFO][zipline.data.bundles.core]
Ingesting quandl
[2025-11-02T17:31:05-0600-INFO][zipline.data.bundles.quandl]
Downloading WIKI metadata.
[2025-11-02T17:32:17-0600-INFO][zipline.data.bundles.quandl]
Parsing raw data.
[2025-11-02T17:32:39-0600-INFO][zipline.data.bundles.quandl]
Generating asset metadata.
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\data\bundles\quandl.py:107: FutureWarning: The provided callable <function min at 0x00000288B4185DA0> is currently using SeriesGroupBy.min. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string "min" instead.
data = data.groupby(by="symbol").agg({"date": [np.min, np.max]})
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\data\bundles\quandl.py:107: FutureWarning: The provided callable <function max at 0x00000288B4185D00> is currently using SeriesGroupBy.max. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string "max" instead.
data = data.groupby(by="symbol").agg({"date": [np.min, np.max]})
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\assets\asset_writer.py:321: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
mappings.groupby(["symbol", "country_code"], group_keys=False).apply(
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\data\bcolz_daily_bars.py:341: UserWarning: Ignoring 1 values because they are out of bounds for uint32:
open high low close volume ex_dividend split_ratio
2011-04-11 1.79 1.84 1.55 1.7 6.674913e+09 0.0 1.0
winsorise_uint32(raw_data, invalid_data_behavior, "volume", *OHLC)
[2025-11-02T17:34:43-0600-INFO][zipline.data.bundles.quandl]
Parsing split data.
[2025-11-02T17:34:43-0600-INFO][zipline.data.bundles.quandl]
Parsing dividend data.
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=67, ex_date=2017-11-09, amount=0.620
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=93, ex_date=2017-11-09, amount=0.240
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=161, ex_date=2017-11-09, amount=0.110
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=283, ex_date=2017-11-09, amount=0.415
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=298, ex_date=2017-11-09, amount=1.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=318, ex_date=2017-11-09, amount=0.330
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=434, ex_date=2017-11-09, amount=0.110
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=516, ex_date=1996-05-30, amount=0.310
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=524, ex_date=2017-11-09, amount=0.050
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=556, ex_date=2017-11-09, amount=0.075
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=578, ex_date=2017-11-09, amount=0.160
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=605, ex_date=2017-11-09, amount=0.040
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=666, ex_date=1990-03-26, amount=0.140
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=694, ex_date=1990-03-27, amount=0.100
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=723, ex_date=2017-11-09, amount=1.620
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=758, ex_date=2017-11-09, amount=0.500
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=788, ex_date=2017-11-09, amount=0.060
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=859, ex_date=1995-05-09, amount=0.100
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=904, ex_date=2017-11-09, amount=0.135
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=975, ex_date=2017-11-09, amount=0.030
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1057, ex_date=2017-11-09, amount=0.250
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1088, ex_date=1990-03-26, amount=0.240
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1091, ex_date=2017-11-09, amount=0.075
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1111, ex_date=1993-03-04, amount=0.070
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1172, ex_date=2017-11-09, amount=0.130
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1209, ex_date=2017-11-09, amount=0.010
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1322, ex_date=1995-05-25, amount=0.150
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1441, ex_date=2017-11-09, amount=1.500
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1525, ex_date=2017-11-09, amount=0.090
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1600, ex_date=2015-07-06, amount=16.500
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1642, ex_date=2017-11-09, amount=0.270
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1748, ex_date=2017-11-09, amount=0.740
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1876, ex_date=2017-11-09, amount=0.120
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1922, ex_date=2017-11-09, amount=0.040
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=1947, ex_date=1990-03-26, amount=0.150
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2098, ex_date=2017-11-09, amount=0.200
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2118, ex_date=2014-11-06, amount=0.050
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2120, ex_date=2017-11-09, amount=0.110
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2149, ex_date=2017-11-09, amount=0.330
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2204, ex_date=2017-11-09, amount=0.320
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2220, ex_date=2017-11-09, amount=0.660
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2281, ex_date=2017-11-09, amount=0.450
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2389, ex_date=2017-11-09, amount=0.140
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2441, ex_date=2017-11-09, amount=0.215
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2517, ex_date=2017-11-09, amount=0.080
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2582, ex_date=2017-11-09, amount=0.780
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2622, ex_date=2017-11-09, amount=0.390
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2662, ex_date=2015-01-14, amount=0.750
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2754, ex_date=2000-12-27, amount=0.250
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2754, ex_date=2009-09-11, amount=0.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2754, ex_date=2009-12-11, amount=0.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2754, ex_date=2010-03-11, amount=0.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2754, ex_date=2010-12-15, amount=0.180
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2766, ex_date=2017-11-09, amount=0.320
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2798, ex_date=2017-11-09, amount=0.065
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2817, ex_date=1992-03-03, amount=0.300
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2824, ex_date=2017-11-09, amount=0.120
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2843, ex_date=2017-11-09, amount=0.150
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2857, ex_date=2011-09-07, amount=0.410
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=2968, ex_date=1990-03-26, amount=0.100
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=3005, ex_date=1990-03-26, amount=0.070
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=3078, ex_date=2014-05-12, amount=0.060
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=3117, ex_date=2017-11-09, amount=0.430
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=3138, ex_date=2010-08-16, amount=0.060
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Couldn't compute ratio for dividend sid=3145, ex_date=2017-11-09, amount=0.050
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=501, ex_date=2006-01-03, amount=41.560
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=1557, ex_date=2007-07-02, amount=88.530
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=1632, ex_date=2000-07-13, amount=181.000
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=1657, ex_date=2013-09-30, amount=21.355
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=1775, ex_date=1994-12-01, amount=76.000
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=1776, ex_date=1996-11-04, amount=36.708
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=2455, ex_date=2016-10-03, amount=25.611
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=2687, ex_date=2008-06-26, amount=10.000
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=2900, ex_date=2007-07-02, amount=88.530
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
Dividend ratio <= 0 for dividend sid=3088, ex_date=2015-04-27, amount=31.291
In [45]:
start = pd.Timestamp('1998-01-01')
end = pd.Timestamp('2018-12-31')
live_start_date = '2006-02-27'
tickers = ['AAPL', 'WMT', 'XOM',
#'GOOGL', 'MSFT', 'NVDA', 'AMD', 'INTC', 'ORCL',
# 'BIDU',
# 'COST', 'PG', 'KO', 'PEP',
# 'CME', 'AVGO', 'WMT', 'JNJ', 'XOM',
# 'HD',
# 'EQIX',
# 'ABBV', 'SCHD', 'PFF', 'VWO', 'VEA, 'GLD', 'FXY','FXE','VNQ', 'TLT',
]
In [46]:
from zipline.api import symbol
def initialize(context):
context.universe = [symbol(s) for s in tickers]
# History window
context.history_window = 20
# Size of our portfolio
context.stocks_to_hold = 10
# Schedule the daily trading routine for once per month
schedule_function(handle_data, date_rules.month_start(), time_rules.market_close())
def month_perf(ts):
perf = (ts[-1] / ts[0]) - 1
return perf
def handle_data(context, data):
# Get history for all the stocks.
hist = data.history(context.universe, "close", context.history_window, "1d")
# This creates a table of percent returns, in order.
perf_table = hist.apply(month_perf).sort_values(ascending=False)
# Make buy list of the top N stocks
buy_list = perf_table[:context.stocks_to_hold]
# The rest will not be held.
the_rest = perf_table[context.stocks_to_hold:]
# Place target buy orders for top N stocks.
for stock, perf in buy_list.items():
stock_weight = 1 / context.stocks_to_hold
# Place order
if data.can_trade(stock):
order_target_percent(stock, stock_weight)
# Make sure we are flat the rest.
for stock, perf in the_rest.items():
# Place order
if data.can_trade(stock):
order_target_percent(stock, 0.0)
def analyze(context, perf):
fig = plt.figure(figsize=(12, 8))
# First chart
ax = fig.add_subplot(311)
ax.set_title('Strategy Results')
ax.plot(perf.index, perf['portfolio_value'], linestyle='-',
label='Equity Curve', linewidth=3.0)
ax.legend()
ax.grid(False)
# Second chart
ax = fig.add_subplot(312)
ax.plot(perf.index, perf['gross_leverage'],
label='Exposure', linestyle='-', linewidth=1.0)
ax.legend()
ax.grid(True)
#Use PyFolio to generate a performance report
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
live_start_date=live_start_date, round_trips=True)
In [47]:
algo1_momentum_results = run_algorithm(start=start, end=end,
initialize=initialize, analyze=analyze,
handle_data=handle_data,
capital_base=10000,
data_frequency = 'daily', bundle='quandl')
C:\Users\Sujala\AppData\Local\Temp\tmpe964z5zr\ipykernel_11880\1736499118.py:15: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]` perf = (ts[-1] / ts[0]) - 1 C:\Users\Sujala\AppData\Local\Temp\tmpe964z5zr\ipykernel_11880\1736499118.py:15: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]` perf = (ts[-1] / ts[0]) - 1 c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '7.725%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '3.613%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '5.189%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
| Start date | 1998-01-02 | |||
|---|---|---|---|---|
| End date | 2018-12-31 | |||
| In-sample months | 97 | |||
| Out-of-sample months | 154 | |||
| In-sample | Out-of-sample | All | ||
| Annual return | 7.725% | 3.613% | 5.189% | |
| Cumulative returns | 83.131% | 57.688% | 188.776% | |
| Annual volatility | 8.056% | 5.591% | 6.657% | |
| Sharpe ratio | 0.96 | 0.66 | 0.79 | |
| Calmar ratio | 0.58 | 0.31 | 0.39 | |
| Stability | 0.73 | 0.93 | 0.96 | |
| Max drawdown | -13.356% | -11.657% | -13.356% | |
| Omega ratio | 1.18 | 1.14 | 1.16 | |
| Sortino ratio | 1.40 | 0.96 | 1.15 | |
| Skew | -0.58 | 0.22 | -0.30 | |
| Kurtosis | 9.11 | 11.90 | 11.56 | |
| Tail ratio | 1.13 | 1.03 | 1.08 | |
| Daily value at risk | -0.984% | -0.69% | -0.818% | |
| Gross leverage | 0.30 | 0.30 | 0.30 | |
| Daily turnover | 0.85% | 0.282% | 0.511% | |
| Worst drawdown periods | Net drawdown in % | Peak date | Valley date | Recovery date | Duration |
|---|---|---|---|---|---|
| 0 | 13.36 | 2000-04-03 | 2002-07-23 | 2004-04-15 | 1054 |
| 1 | 11.66 | 2008-06-05 | 2009-03-09 | 2009-11-17 | 379 |
| 2 | 7.71 | 2015-02-17 | 2016-01-20 | 2017-05-03 | 577 |
| 3 | 5.74 | 2007-12-26 | 2008-03-10 | 2008-04-21 | 84 |
| 4 | 5.37 | 2012-09-21 | 2013-04-18 | 2013-12-26 | 330 |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]` starting_value=is_cum_returns[-1], c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]` starting_value=is_cum_returns[-1], c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator. ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
| Stress Events | mean | min | max |
|---|---|---|---|
| Dotcom | 0.02% | -1.28% | 1.52% |
| Lehman | -0.08% | -2.96% | 1.37% |
| 9/11 | 0.11% | -1.20% | 1.11% |
| US downgrade/European Debt Crisis | 0.01% | -1.51% | 1.13% |
| Fukushima | 0.01% | -0.84% | 0.58% |
| US Housing | -0.08% | -0.73% | 0.81% |
| EZB IR Event | -0.01% | -0.36% | 0.53% |
| Aug07 | 0.01% | -1.47% | 1.02% |
| Mar08 | 0.13% | -0.76% | 1.41% |
| Sept08 | -0.19% | -2.96% | 1.37% |
| 2009Q1 | -0.05% | -1.23% | 1.04% |
| 2009Q2 | 0.09% | -0.82% | 1.65% |
| Flash Crash | -0.17% | -1.02% | 0.94% |
| Apr14 | 0.08% | -0.32% | 0.79% |
| Oct14 | 0.04% | -0.51% | 0.60% |
| Fall2015 | -0.06% | -1.19% | 1.38% |
| Low Volatility Bull Market | 0.03% | -1.36% | 1.17% |
| GFC Crash | 0.00% | -2.96% | 3.76% |
| Recovery | 0.03% | -1.51% | 1.13% |
| New Normal | 0.01% | -1.19% | 1.38% |
| Top 10 long positions of all time | max |
|---|---|
| sid | |
| WMT | 19.88% |
| XOM | 19.59% |
| AAPL | 19.38% |
| Top 10 short positions of all time | max |
|---|---|
| sid |
| Top 10 positions of all time | max |
|---|---|
| sid | |
| WMT | 19.88% |
| XOM | 19.59% |
| AAPL | 19.38% |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
| Summary stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total number of round_trips | 958.00 | 87.00 | 871.00 |
| Percent profitable | 0.69 | 0.54 | 0.70 |
| Winning round_trips | 657.00 | 47.00 | 610.00 |
| Losing round_trips | 301.00 | 40.00 | 261.00 |
| Even round_trips | 0.00 | 0.00 | 0.00 |
| PnL stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total profit | $5824.21 | $-339.46 | $6163.67 |
| Gross profit | $11487.42 | $1713.98 | $9773.44 |
| Gross loss | $-5663.21 | $-2053.44 | $-3609.77 |
| Profit factor | $2.03 | $0.83 | $2.71 |
| Avg. trade net profit | $6.08 | $-3.90 | $7.08 |
| Avg. winning trade | $17.48 | $36.47 | $16.02 |
| Avg. losing trade | $-18.81 | $-51.34 | $-13.83 |
| Ratio Avg. Win:Avg. Loss | $0.93 | $0.71 | $1.16 |
| Largest winning trade | $212.44 | $112.43 | $212.44 |
| Largest losing trade | $-408.10 | $-408.10 | $-213.59 |
| Duration stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg duration | 402 days 03:53:32.943632568 | 880 days 05:41:22.758620688 | 354 days 09:49:48.289322616 |
| Median duration | 212 days 12:00:00 | 438 days 01:00:00 | 210 days 23:00:00 |
| Longest duration | 3028 days 01:00:00 | 3028 days 01:00:00 | 1328 days 01:00:00 |
| Shortest duration | 1 days 00:00:00 | 9 days 00:00:00 | 1 days 00:00:00 |
| Return stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg returns all round_trips | 0.04% | -0.01% | 0.04% |
| Avg returns winning | 0.11% | 0.17% | 0.10% |
| Avg returns losing | -0.11% | -0.23% | -0.09% |
| Median returns all round_trips | 0.04% | 0.02% | 0.04% |
| Median returns winning | 0.07% | 0.14% | 0.07% |
| Median returns losing | -0.05% | -0.13% | -0.04% |
| Largest winning trade | 1.80% | 0.56% | 1.80% |
| Largest losing trade | -1.59% | -1.59% | -1.55% |
| Symbol stats | AAPL | WMT | XOM |
|---|---|---|---|
| Avg returns all round_trips | 0.05% | 0.04% | 0.02% |
| Avg returns winning | 0.13% | 0.07% | 0.08% |
| Avg returns losing | -0.15% | -0.03% | -0.11% |
| Median returns all round_trips | 0.04% | 0.03% | 0.04% |
| Median returns winning | 0.09% | 0.05% | 0.07% |
| Median returns losing | -0.07% | -0.02% | -0.05% |
| Largest winning trade | 1.80% | 0.46% | 0.27% |
| Largest losing trade | -1.59% | -0.13% | -0.98% |
| Profitability (PnL / PnL total) per name | |
|---|---|
| symbol | |
| AAPL | 51.69% |
| WMT | 36.24% |
| XOM | 12.08% |
In [49]:
# moving average strategy
from zipline.api import order_target, record, symbol
from zipline.finance import commission, slippage
def initialize(context):
context.universe = [symbol(s) for s in tickers]
context.history_window_long = 300
context.history_window_short = 100
context.i = 0
# Set commission and slippage
context.set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1.0))
context.set_slippage(slippage.VolumeShareSlippage())
schedule_function(handle_data, date_rules.every_day(), time_rules.market_close())
def handle_data(context, perf):
# Skip first 300 days to get full windows
context.i += 1
if context.i < 300:
return
rebalance(context, perf)
def rebalance(context, perf):
for asset in context.universe:
if not perf.can_trade(asset):
continue
short_mavg = perf.history(asset, 'price', context.history_window_short, '1d').mean()
long_mavg = perf.history(asset, 'price', context.history_window_long, '1d').mean()
if short_mavg > long_mavg:
weight = 1.0 / len(context.universe)
order_target_percent(asset, weight)
elif short_mavg < long_mavg:
order_target_percent(asset, 0.0)
def analyze(context, perf):
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(211)
perf['portfolio_value'].plot(ax=ax1)
ax1.set_ylabel("Portfolio value (USD)")
plt.show()
#Use PyFolio to generate a performance report
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
live_start_date=live_start_date, round_trips=True)
In [50]:
algo2_dma_results = run_algorithm(start=start, end=end,
initialize=initialize, analyze=analyze,
handle_data=handle_data,
capital_base=10000,
data_frequency = 'daily', bundle='quandl')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '2.738%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '8.169%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '6.029%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
| Start date | 1998-01-02 | |||
|---|---|---|---|---|
| End date | 2018-12-31 | |||
| In-sample months | 97 | |||
| Out-of-sample months | 154 | |||
| In-sample | Out-of-sample | All | ||
| Annual return | 2.738% | 8.169% | 6.029% | |
| Cumulative returns | 24.562% | 173.936% | 241.218% | |
| Annual volatility | 25.853% | 15.909% | 20.349% | |
| Sharpe ratio | 0.24 | 0.57 | 0.39 | |
| Calmar ratio | 0.04 | 0.38 | 0.09 | |
| Stability | 0.17 | 0.89 | 0.73 | |
| Max drawdown | -68.795% | -21.591% | -68.795% | |
| Omega ratio | 1.05 | 1.12 | 1.08 | |
| Sortino ratio | 0.32 | 0.83 | 0.55 | |
| Skew | -0.83 | 0.06 | -0.65 | |
| Kurtosis | 11.67 | 10.84 | 14.99 | |
| Tail ratio | 1.03 | 0.99 | 0.99 | |
| Daily value at risk | -3.233% | -1.968% | -2.532% | |
| Gross leverage | 0.97 | 0.90 | 0.93 | |
| Daily turnover | 55.059% | 51.315% | 52.707% | |
| Worst drawdown periods | Net drawdown in % | Peak date | Valley date | Recovery date | Duration |
|---|---|---|---|---|---|
| 0 | 68.80 | 2000-04-03 | 2002-09-27 | 2009-10-20 | 2492 |
| 1 | 19.36 | 2018-01-18 | 2018-03-27 | NaT | NaN |
| 2 | 16.93 | 2012-09-21 | 2013-02-04 | 2014-07-07 | 467 |
| 3 | 16.19 | 2000-01-20 | 2000-02-25 | 2000-03-21 | 44 |
| 4 | 15.35 | 1998-08-21 | 1998-08-31 | 1998-11-06 | 56 |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
d = d.astype('datetime64[us]')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
| Stress Events | mean | min | max |
|---|---|---|---|
| Dotcom | 0.05% | -3.91% | 5.09% |
| Lehman | -0.08% | -4.26% | 4.73% |
| 9/11 | 0.14% | -3.68% | 2.10% |
| US downgrade/European Debt Crisis | 0.03% | -5.24% | 4.00% |
| Fukushima | -0.03% | -3.47% | 1.33% |
| US Housing | 0.00% | 0.00% | 0.00% |
| EZB IR Event | -0.04% | -1.18% | 1.75% |
| Aug07 | 0.03% | -4.86% | 3.41% |
| Mar08 | 0.44% | -2.46% | 4.91% |
| Sept08 | -0.23% | -4.26% | 4.73% |
| 2009Q1 | -0.11% | -2.48% | 1.49% |
| 2009Q2 | 0.09% | -1.18% | 1.34% |
| Flash Crash | -0.32% | -2.14% | 2.61% |
| Apr14 | 0.27% | -1.08% | 2.60% |
| Oct14 | 0.14% | -1.72% | 1.97% |
| Fall2015 | -0.05% | -2.04% | 2.70% |
| Low Volatility Bull Market | 0.07% | -4.50% | 3.83% |
| GFC Crash | 0.06% | -5.09% | 9.92% |
| Recovery | 0.05% | -5.24% | 4.00% |
| New Normal | 0.01% | -10.14% | 3.75% |
| Top 10 long positions of all time | max |
|---|---|
| sid | |
| XOM | 162.89% |
| WMT | 106.03% |
| AAPL | 70.83% |
| Top 10 short positions of all time | max |
|---|---|
| sid | |
| XOM | -101.61% |
| AAPL | -65.30% |
| WMT | -43.43% |
| Top 10 positions of all time | max |
|---|---|
| sid | |
| XOM | 162.89% |
| WMT | 106.03% |
| AAPL | 70.83% |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
| Summary stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total number of round_trips | 5108.00 | 1985.00 | 3123.00 |
| Percent profitable | 0.51 | 0.45 | 0.55 |
| Winning round_trips | 2600.00 | 894.00 | 1706.00 |
| Losing round_trips | 2508.00 | 1091.00 | 1417.00 |
| Even round_trips | 0.00 | 0.00 | 0.00 |
| PnL stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total profit | $-22608.05 | $-10279.02 | $-12329.02 |
| Gross profit | $217735.46 | $139266.06 | $78469.40 |
| Gross loss | $-240343.50 | $-149545.08 | $-90798.42 |
| Profit factor | $0.91 | $0.93 | $0.86 |
| Avg. trade net profit | $-4.43 | $-5.18 | $-3.95 |
| Avg. winning trade | $83.74 | $155.78 | $46.00 |
| Avg. losing trade | $-95.83 | $-137.07 | $-64.08 |
| Ratio Avg. Win:Avg. Loss | $0.87 | $1.14 | $0.72 |
| Largest winning trade | $2779.44 | $2779.44 | $1077.15 |
| Largest losing trade | $-13563.72 | $-8505.15 | $-13563.72 |
| Duration stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg duration | 44 days 11:29:35.332811276 | 43 days 05:57:22.216624685 | 45 days 06:16:01.383285302 |
| Median duration | 3 days 00:00:00 | 1 days 00:00:00 | 7 days 00:00:00 |
| Longest duration | 1162 days 00:00:00 | 1162 days 00:00:00 | 372 days 00:00:00 |
| Shortest duration | 0 days 21:00:00 | 0 days 21:00:00 | 0 days 21:00:00 |
| Return stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg returns all round_trips | -0.02% | -0.03% | -0.01% |
| Avg returns winning | 0.44% | 0.78% | 0.26% |
| Avg returns losing | -0.49% | -0.70% | -0.33% |
| Median returns all round_trips | 0.00% | -0.03% | 0.01% |
| Median returns winning | 0.16% | 0.32% | 0.10% |
| Median returns losing | -0.16% | -0.27% | -0.10% |
| Largest winning trade | 8.69% | 8.69% | 5.14% |
| Largest losing trade | -38.94% | -31.07% | -38.94% |
| Symbol stats | AAPL | WMT | XOM |
|---|---|---|---|
| Avg returns all round_trips | -0.01% | -0.01% | -0.03% |
| Avg returns winning | 0.98% | 0.25% | 0.31% |
| Avg returns losing | -1.00% | -0.28% | -0.40% |
| Median returns all round_trips | -0.00% | 0.00% | 0.00% |
| Median returns winning | 0.41% | 0.12% | 0.10% |
| Median returns losing | -0.43% | -0.12% | -0.11% |
| Largest winning trade | 8.36% | 3.37% | 8.69% |
| Largest losing trade | -31.07% | -4.57% | -38.94% |
| Profitability (PnL / PnL total) per name | |
|---|---|
| symbol | |
| XOM | 97.13% |
| AAPL | 9.04% |
| WMT | -6.17% |
In [51]:
def initialize_mean_reversion(context):
context.universe = [symbol(s) for s in tickers]
context.lookback = 20
context.z_entry = 1.0
context.z_exit = 0.25
schedule_function(mean_reversion_rebalance, date_rules.every_day(), time_rules.market_close())
def mean_reversion_rebalance(context, data):
price_history = data.history(context.universe, 'price', context.lookback, '1d')
mean_price = price_history.mean()
std_price = price_history.std()
for asset in context.universe:
if not data.can_trade(asset):
continue
z_score = (data.current(asset, 'price') - mean_price[asset]) / std_price[asset]
if z_score < -context.z_entry:
order_target_percent(asset, 0.25) # go long
elif z_score > context.z_entry:
order_target_percent(asset, -0.25) # go short
elif abs(z_score) < context.z_exit:
order_target_percent(asset, 0)
def analyze(context, perf):
import matplotlib.pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(311)
perf['portfolio_value'].plot(ax=ax1)
ax1.set_ylabel("Portfolio value (USD)")
plt.show()
#Use PyFolio to generate a performance report
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
live_start_date=live_start_date, round_trips=True)
In [52]:
algo3_mean_rev_results = run_algorithm(
start=start,
end=end,
initialize=initialize_mean_reversion, analyze=analyze,
capital_base=10000,
data_frequency='daily',
bundle='quandl'
)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '2.863%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-1.88%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-0.067%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
| Start date | 1998-01-02 | |||
|---|---|---|---|---|
| End date | 2018-12-31 | |||
| In-sample months | 97 | |||
| Out-of-sample months | 154 | |||
| In-sample | Out-of-sample | All | ||
| Annual return | 2.863% | -1.88% | -0.067% | |
| Cumulative returns | 25.803% | -21.616% | -1.39% | |
| Annual volatility | 15.606% | 10.316% | 12.633% | |
| Sharpe ratio | 0.26 | -0.13 | 0.06 | |
| Calmar ratio | 0.11 | -0.06 | -0.00 | |
| Stability | 0.46 | 0.37 | 0.09 | |
| Max drawdown | -26.336% | -29.731% | -39.361% | |
| Omega ratio | 1.05 | 0.97 | 1.01 | |
| Sortino ratio | 0.36 | -0.20 | 0.08 | |
| Skew | -1.24 | 1.19 | -0.49 | |
| Kurtosis | 20.91 | 21.59 | 25.20 | |
| Tail ratio | 1.07 | 1.10 | 1.05 | |
| Daily value at risk | -1.95% | -1.305% | -1.589% | |
| Gross leverage | 0.57 | 0.59 | 0.59 | |
| Daily turnover | 22.499% | 19.64% | 20.791% | |
| Worst drawdown periods | Net drawdown in % | Peak date | Valley date | Recovery date | Duration |
|---|---|---|---|---|---|
| 0 | 39.36 | 2003-03-13 | 2008-10-09 | NaT | NaN |
| 1 | 26.34 | 2000-06-27 | 2000-10-12 | 2002-03-25 | 455 |
| 2 | 19.52 | 1998-01-02 | 1998-08-21 | 1998-10-13 | 203 |
| 3 | 14.28 | 1999-10-19 | 1999-12-07 | 2000-04-28 | 139 |
| 4 | 9.97 | 2002-06-05 | 2002-07-22 | 2002-08-28 | 61 |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
d = d.astype('datetime64[us]')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
| Stress Events | mean | min | max |
|---|---|---|---|
| Dotcom | -0.00% | -3.68% | 2.98% |
| Lehman | -0.13% | -3.37% | 2.61% |
| 9/11 | -0.12% | -2.99% | 2.66% |
| US downgrade/European Debt Crisis | 0.19% | -3.08% | 2.56% |
| Fukushima | 0.07% | -0.63% | 1.23% |
| US Housing | 0.06% | -1.84% | 2.03% |
| EZB IR Event | -0.03% | -0.82% | 0.82% |
| Aug07 | -0.13% | -3.68% | 2.09% |
| Mar08 | -0.23% | -1.89% | 1.25% |
| Sept08 | -0.31% | -3.37% | 2.61% |
| 2009Q1 | 0.20% | -2.31% | 2.25% |
| 2009Q2 | -0.03% | -1.71% | 2.71% |
| Flash Crash | -0.01% | -0.60% | 0.50% |
| Apr14 | -0.09% | -1.49% | 0.50% |
| Oct14 | 0.06% | -0.83% | 1.47% |
| Fall2015 | -0.01% | -2.97% | 3.48% |
| Low Volatility Bull Market | 0.00% | -2.32% | 3.22% |
| GFC Crash | -0.00% | -5.80% | 9.14% |
| Recovery | -0.00% | -3.08% | 2.56% |
| New Normal | -0.01% | -3.41% | 3.48% |
| Top 10 long positions of all time | max |
|---|---|
| sid | |
| AAPL | 29.22% |
| WMT | 28.38% |
| XOM | 27.64% |
| Top 10 short positions of all time | max |
|---|---|
| sid | |
| AAPL | -31.20% |
| XOM | -28.74% |
| WMT | -28.70% |
| Top 10 positions of all time | max |
|---|---|
| sid | |
| AAPL | 31.20% |
| XOM | 28.74% |
| WMT | 28.70% |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:317: RuntimeWarning: divide by zero encountered in divide
ending_price = ending_val / ending_amount
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
| Summary stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total number of round_trips | 2034.00 | 1330.00 | 704.00 |
| Percent profitable | 0.43 | 0.32 | 0.63 |
| Winning round_trips | 870.00 | 428.00 | 442.00 |
| Losing round_trips | 1164.00 | 902.00 | 262.00 |
| Even round_trips | 0.00 | 0.00 | 0.00 |
| PnL stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total profit | $-331.16 | $-444.28 | $113.12 |
| Gross profit | $111328.58 | $29710.70 | $81617.88 |
| Gross loss | $-111659.74 | $-30154.98 | $-81504.76 |
| Profit factor | $1.00 | $0.99 | $1.00 |
| Avg. trade net profit | $-0.16 | $-0.33 | $0.16 |
| Avg. winning trade | $127.96 | $69.42 | $184.66 |
| Avg. losing trade | $-95.93 | $-33.43 | $-311.09 |
| Ratio Avg. Win:Avg. Loss | $1.33 | $2.08 | $0.59 |
| Largest winning trade | $2210.67 | $673.43 | $2210.67 |
| Largest losing trade | $-14455.18 | $-699.06 | $-14455.18 |
| Duration stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg duration | 30 days 12:37:08.319075712 | 21 days 14:13:10.375939849 | 47 days 09:39:48.069602272 |
| Median duration | 16 days 00:00:00 | 16 days 00:00:00 | 15 days 00:00:00 |
| Longest duration | 418 days 00:00:00 | 186 days 01:00:00 | 418 days 00:00:00 |
| Shortest duration | 0 days 21:00:00 | 0 days 21:00:00 | 1 days 00:00:00 |
| Return stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg returns all round_trips | -0.02% | -0.01% | -0.03% |
| Avg returns winning | 1.09% | 0.59% | 1.56% |
| Avg returns losing | -0.83% | -0.28% | -2.76% |
| Median returns all round_trips | -0.01% | -0.02% | 0.12% |
| Median returns winning | 0.50% | 0.38% | 0.61% |
| Median returns losing | -0.06% | -0.05% | -0.24% |
| Largest winning trade | 18.52% | 5.73% | 18.52% |
| Largest losing trade | -144.94% | -6.31% | -144.94% |
| Symbol stats | AAPL | WMT | XOM |
|---|---|---|---|
| Avg returns all round_trips | -0.09% | 0.03% | 0.01% |
| Avg returns winning | 2.09% | 0.58% | 0.49% |
| Avg returns losing | -1.90% | -0.29% | -0.37% |
| Median returns all round_trips | -0.01% | -0.02% | -0.01% |
| Median returns winning | 0.99% | 0.46% | 0.24% |
| Median returns losing | -0.09% | -0.05% | -0.06% |
| Largest winning trade | 18.52% | 2.99% | 5.73% |
| Largest losing trade | -144.94% | -4.21% | -12.41% |
| Profitability (PnL / PnL total) per name | |
|---|---|
| symbol | |
| AAPL | 1324.83% |
| XOM | -127.54% |
| WMT | -1097.29% |
In [53]:
def initialize_regime_switch(context):
context.universe = [symbol(s) for s in tickers]
context.market_asset = symbol("BRK_A")
context.vol_lookback = 30
context.breakout_window = 60
context.stable_vol = 0.012
context.breakout_return = 0.04
context.breakout_buffer = 0.002
context.crisis_vol = 0.035
context.crisis_drawdown = -0.15
context.momentum_lookback = 90
context.momentum_top_n = 8
context.momentum_alloc = 1.0
context.mr_lookback = 20
context.mr_entry = 1.0
context.mr_exit = 0.25
context.mr_long_alloc = 0.45
context.mr_short_alloc = 0.45
context.market_history_window = context.vol_lookback + context.breakout_window + 1
context.min_history = max(
context.market_history_window,
context.momentum_lookback + 1,
context.mr_lookback
)
context.regime_codes = {"crisis": -1, "mean_reversion": 0, "momentum": 1}
context.current_regime = "neutral"
set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1.0))
set_slippage(slippage.VolumeShareSlippage())
schedule_function(regime_rebalance, date_rules.every_day(), time_rules.market_close())
def regime_rebalance(context, data):
regime, realized_vol, drawdown = detect_regime(context, data)
if regime is None:
return
context.current_regime = regime
if realized_vol is not None and drawdown is not None:
record(
regime_code=context.regime_codes.get(regime, 0),
realized_vol=realized_vol,
drawdown=drawdown
)
if regime == "crisis":
liquidate_universe(context, data)
elif regime == "momentum":
apply_momentum(context, data)
else:
apply_mean_reversion(context, data)
def detect_regime(context, data):
try:
prices = data.history(
context.market_asset,
"close",
context.market_history_window,
"1d"
).dropna()
except Exception:
return None, None, None
if len(prices) < context.market_history_window:
return None, None, None
recent_returns = prices.pct_change().dropna().iloc[-context.vol_lookback:]
if recent_returns.empty:
return None, None, None
realized_vol = float(recent_returns.std())
drawdown_window = prices.iloc[-context.vol_lookback:]
drawdown = float(drawdown_window.iloc[-1] / drawdown_window.max() - 1)
window_return = float(prices.iloc[-1] / prices.iloc[-context.breakout_window] - 1)
breakout_high = float(prices.iloc[-context.breakout_window:].max())
breakout_condition = prices.iloc[-1] >= breakout_high * (1 - context.breakout_buffer)
if drawdown <= context.crisis_drawdown or realized_vol >= context.crisis_vol:
return "crisis", realized_vol, drawdown
if realized_vol <= context.stable_vol:
return "mean_reversion", realized_vol, drawdown
if breakout_condition and window_return >= context.breakout_return:
return "momentum", realized_vol, drawdown
return "mean_reversion", realized_vol, drawdown
def apply_momentum(context, data):
try:
price_history = data.history(
context.universe,
"close",
context.momentum_lookback + 1,
"1d"
).dropna()
except Exception:
return
if len(price_history) < context.momentum_lookback + 1:
return
momentum_scores = price_history.iloc[-1] / price_history.iloc[0] - 1
momentum_scores = momentum_scores.dropna().sort_values(ascending=False)
if momentum_scores.empty:
liquidate_universe(context, data)
return
selected = momentum_scores.head(context.momentum_top_n)
target_weights = {}
if not selected.empty:
weight = context.momentum_alloc / len(selected)
for asset in selected.index:
target_weights[asset] = weight
apply_target_weights(context, data, target_weights)
def apply_mean_reversion(context, data):
try:
price_history = data.history(
context.universe,
"close",
context.mr_lookback,
"1d"
).dropna()
except Exception:
return
if len(price_history) < context.mr_lookback:
return
means = price_history.mean()
stds = price_history.std().replace(0, pd.NA)
z_scores = ((price_history.iloc[-1] - means) / stds).dropna()
if z_scores.empty:
liquidate_universe(context, data)
return
long_candidates = z_scores[z_scores <= -context.mr_entry].sort_values()
short_candidates = z_scores[z_scores >= context.mr_entry].sort_values(ascending=False)
flat_candidates = z_scores[(z_scores.abs() < context.mr_exit)].index
target_weights = {}
if len(long_candidates) > 0 and context.mr_long_alloc > 0:
weight = context.mr_long_alloc / len(long_candidates)
for asset in long_candidates.index:
target_weights[asset] = weight
if len(short_candidates) > 0 and context.mr_short_alloc > 0:
weight = context.mr_short_alloc / len(short_candidates)
for asset in short_candidates.index:
target_weights[asset] = -weight
for asset in flat_candidates:
target_weights.setdefault(asset, 0.0)
apply_target_weights(context, data, target_weights)
def liquidate_universe(context, data):
for asset in context.universe:
if data.can_trade(asset):
order_target_percent(asset, 0.0)
def apply_target_weights(context, data, target_weights):
for asset in context.universe:
weight = target_weights.get(asset, 0.0)
if data.can_trade(asset):
order_target_percent(asset, weight)
def handle_data_regime(context, data):
pass
def analyze_regime(context, perf):
fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
perf["portfolio_value"].plot(ax=axes[0], label="Equity Curve", linewidth=2.0)
axes[0].set_title("Regime-Switching Strategy")
axes[0].legend()
axes[0].grid(False)
if "returns" in perf:
cumulative = (1.0 + perf["returns"]).cumprod() - 1.0
cumulative.plot(ax=axes[1], label="Cumulative Return")
axes[1].set_ylabel("Cumulative Return")
axes[1].legend()
axes[1].grid(True)
plt.tight_layout()
returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
live_start_date=live_start_date, round_trips=True)
In [54]:
algo4_regime_results = run_algorithm(
start=start,
end=end,
initialize=initialize_regime_switch,
handle_data=handle_data_regime,
analyze=analyze_regime,
capital_base=10000,
data_frequency="daily",
bundle="quandl"
)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-1.38%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-4.798%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%" c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-3.487%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first. perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
| Start date | 1998-01-02 | |||
|---|---|---|---|---|
| End date | 2018-12-31 | |||
| In-sample months | 97 | |||
| Out-of-sample months | 154 | |||
| In-sample | Out-of-sample | All | ||
| Annual return | -1.38% | -4.798% | -3.487% | |
| Cumulative returns | -10.686% | -46.796% | -52.482% | |
| Annual volatility | 16.809% | 9.048% | 12.636% | |
| Sharpe ratio | 0.00 | -0.50 | -0.22 | |
| Calmar ratio | -0.04 | -0.09 | -0.05 | |
| Stability | 0.12 | 0.90 | 0.90 | |
| Max drawdown | -38.939% | -52.126% | -67.478% | |
| Omega ratio | 1.00 | 0.91 | 0.96 | |
| Sortino ratio | 0.00 | -0.71 | -0.30 | |
| Skew | -1.08 | 0.19 | -0.92 | |
| Kurtosis | 16.25 | 5.17 | 21.62 | |
| Tail ratio | 1.04 | 1.05 | 1.04 | |
| Daily value at risk | -2.118% | -1.158% | -1.603% | |
| Gross leverage | 0.57 | 0.55 | 0.56 | |
| Daily turnover | 54.476% | 47.458% | 50.266% | |
| Worst drawdown periods | Net drawdown in % | Peak date | Valley date | Recovery date | Duration |
|---|---|---|---|---|---|
| 0 | 67.48 | 1999-07-16 | 2018-01-23 | NaT | NaN |
| 1 | 15.44 | 1998-01-02 | 1998-03-19 | 1998-10-09 | 201 |
| 2 | 5.12 | 1999-02-12 | 1999-03-11 | 1999-04-21 | 49 |
| 3 | 5.00 | 1998-12-11 | 1998-12-29 | 1999-01-15 | 26 |
| 4 | 4.39 | 1999-04-29 | 1999-05-04 | 1999-05-11 | 9 |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
d = d.astype('datetime64[us]')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
| Stress Events | mean | min | max |
|---|---|---|---|
| Dotcom | -0.09% | -3.72% | 2.87% |
| Lehman | -0.22% | -3.28% | 2.34% |
| 9/11 | 0.01% | -3.44% | 3.76% |
| US downgrade/European Debt Crisis | 0.22% | -2.23% | 1.87% |
| Fukushima | 0.07% | -1.14% | 1.19% |
| US Housing | 0.00% | -1.14% | 1.21% |
| EZB IR Event | -0.01% | -0.96% | 0.68% |
| Aug07 | 0.09% | -1.84% | 1.31% |
| Mar08 | -0.29% | -2.16% | 2.25% |
| Sept08 | -0.50% | -3.28% | 2.34% |
| 2009Q1 | -0.02% | -1.56% | 1.92% |
| 2009Q2 | 0.04% | -1.22% | 1.78% |
| Flash Crash | -0.16% | -1.52% | 0.60% |
| Apr14 | -0.03% | -0.72% | 0.66% |
| Oct14 | -0.11% | -0.80% | 0.85% |
| Fall2015 | -0.04% | -1.63% | 2.03% |
| Low Volatility Bull Market | -0.01% | -2.67% | 3.04% |
| GFC Crash | -0.05% | -3.28% | 2.85% |
| Recovery | -0.01% | -2.54% | 2.49% |
| New Normal | -0.02% | -3.29% | 3.81% |
| Top 10 long positions of all time | max |
|---|---|
| sid | |
| XOM | 49.12% |
| AAPL | 47.68% |
| WMT | 47.23% |
| Top 10 short positions of all time | max |
|---|---|
| sid | |
| AAPL | -58.56% |
| XOM | -51.48% |
| WMT | -50.50% |
| Top 10 positions of all time | max |
|---|---|
| sid | |
| AAPL | 58.56% |
| XOM | 51.48% |
| WMT | 50.50% |
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:317: RuntimeWarning: divide by zero encountered in divide
ending_price = ending_val / ending_amount
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
warnings.warn("Negative price detected, ignoring for" "round-trip.")
| Summary stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total number of round_trips | 3331.00 | 1903.00 | 1428.00 |
| Percent profitable | 0.51 | 0.43 | 0.61 |
| Winning round_trips | 1693.00 | 817.00 | 876.00 |
| Losing round_trips | 1638.00 | 1086.00 | 552.00 |
| Even round_trips | 0.00 | 0.00 | 0.00 |
| PnL stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Total profit | $-2849.15 | $-3464.64 | $615.49 |
| Gross profit | $121297.72 | $39253.74 | $82043.98 |
| Gross loss | $-124146.87 | $-42718.38 | $-81428.50 |
| Profit factor | $0.98 | $0.92 | $1.01 |
| Avg. trade net profit | $-0.86 | $-1.82 | $0.43 |
| Avg. winning trade | $71.65 | $48.05 | $93.66 |
| Avg. losing trade | $-75.79 | $-39.34 | $-147.52 |
| Ratio Avg. Win:Avg. Loss | $0.95 | $1.22 | $0.63 |
| Largest winning trade | $1338.90 | $1338.90 | $889.30 |
| Largest losing trade | $-12637.90 | $-712.75 | $-12637.90 |
| Duration stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg duration | 20 days 04:51:43.933053137 | 13 days 22:24:09.080399369 | 28 days 13:22:11.093137255 |
| Median duration | 8 days 03:00:00 | 8 days 00:00:00 | 9 days 00:00:00 |
| Longest duration | 288 days 00:00:00 | 178 days 00:00:00 | 288 days 00:00:00 |
| Shortest duration | 0 days 21:00:00 | 0 days 21:00:00 | 1 days 00:00:00 |
| Return stats | All trades | Short trades | Long trades |
|---|---|---|---|
| Avg returns all round_trips | -0.03% | -0.02% | -0.04% |
| Avg returns winning | 0.96% | 0.56% | 1.33% |
| Avg returns losing | -1.03% | -0.44% | -2.26% |
| Median returns all round_trips | 0.00% | -0.02% | 0.13% |
| Median returns winning | 0.46% | 0.33% | 0.67% |
| Median returns losing | -0.22% | -0.20% | -0.28% |
| Largest winning trade | 15.00% | 11.58% | 15.00% |
| Largest losing trade | -231.72% | -5.84% | -231.72% |
| Symbol stats | AAPL | WMT | XOM |
|---|---|---|---|
| Avg returns all round_trips | -0.11% | 0.03% | 0.01% |
| Avg returns winning | 1.61% | 0.43% | 0.60% |
| Avg returns losing | -2.46% | -0.29% | -0.54% |
| Median returns all round_trips | 0.10% | -0.01% | -0.01% |
| Median returns winning | 0.93% | 0.25% | 0.39% |
| Median returns losing | -0.32% | -0.14% | -0.25% |
| Largest winning trade | 15.00% | 3.12% | 4.08% |
| Largest losing trade | -231.72% | -2.92% | -22.41% |
| Profitability (PnL / PnL total) per name | |
|---|---|
| symbol | |
| AAPL | 218.80% |
| XOM | 39.79% |
| WMT | -158.59% |
In [60]:
import numpy as np
import yfinance as yf
import empyrical as ep
def sanitize_series(series):
series = series.copy()
if getattr(series.index, "tz", None) is not None:
series.index = series.index.tz_convert("UTC").tz_localize(None)
return series.sort_index().dropna()
strategy_returns = {
"Monthly_Momentum": sanitize_series(algo1_momentum_results["returns"]),
"Dual_MA": sanitize_series(algo2_dma_results["returns"]),
"Mean_Reversion": sanitize_series(algo3_mean_rev_results["returns"]),
"Regime_Switching": sanitize_series(algo4_regime_results["returns"]),
}
start_date = min(s.index.min() for s in strategy_returns.values())
end_date = max(s.index.max() for s in strategy_returns.values()) + pd.Timedelta(days=1)
bench_tickers = ["SPY", "QQQ", "IEF", "BRK-A"]
bench_prices = yf.download(bench_tickers, start=start_date, end=end_date, auto_adjust=True, progress=False)["Close"]
bench_returns = bench_prices.pct_change().dropna()
def summarize(returns, benchmark):
aligned = returns.reindex(benchmark.index, method="ffill").dropna()
bench_aligned = benchmark.loc[aligned.index]
cumulative = (1 + aligned).prod() - 1
ann_return = ep.annual_return(aligned)
ann_vol = ep.annual_volatility(aligned)
sharpe = ep.sharpe_ratio(aligned)
mdd = ep.max_drawdown(aligned)
alpha, beta = ep.alpha_beta(aligned, bench_aligned)
return pd.Series(
{
"Cumulative Return": cumulative,
"Annual Return": ann_return,
"Annual Volatility": ann_vol,
"Sharpe": sharpe,
"Max Drawdown": mdd,
"Alpha_vs_SPY": alpha,
"Beta_vs_SPY": beta,
}
)
summary_rows = []
for name, series in strategy_returns.items():
summary_rows.append(summarize(series, bench_returns["SPY"]))
for ticker in bench_tickers:
summary_rows.append(
summarize(
bench_returns[ticker],
bench_returns["SPY"],
).rename(index=lambda x: x if not x.startswith("Alpha") else x.replace("_vs_SPY", ""))
)
comparison_df = pd.DataFrame(summary_rows, index=list(strategy_returns.keys()) + bench_tickers)
display(comparison_df.style.format("{:.2%}", subset=["Cumulative Return", "Annual Return", "Annual Volatility", "Max Drawdown"])
.format("{:.2f}", subset=["Sharpe", "Alpha_vs_SPY", "Beta_vs_SPY"])
.set_caption("Strategy vs Benchmark Performance (Daily Returns)"))
# ...existing code...
| Â | Cumulative Return | Annual Return | Annual Volatility | Sharpe | Max Drawdown | Alpha_vs_SPY | Beta_vs_SPY | Alpha |
|---|---|---|---|---|---|---|---|---|
| Monthly_Momentum | 113.21% | 4.72% | 5.71% | 0.84 | -11.66% | 0.02 | 0.24 | nan |
| Dual_MA | 292.02% | 8.68% | 16.80% | 0.58 | -28.03% | 0.06 | 0.44 | nan |
| Mean_Reversion | -25.10% | -1.75% | 10.54% | -0.11 | -39.36% | -0.02 | 0.10 | nan |
| Regime_Switching | -58.81% | -5.26% | 9.60% | -0.52 | -64.65% | -0.05 | 0.02 | nan |
| SPY | 280.93% | 8.49% | 18.54% | 0.53 | -55.19% | nan | 1.00 | 0.000000 |
| QQQ | 619.01% | 12.78% | 21.12% | 0.68 | -53.40% | nan | 1.03 | 0.041955 |
| IEF | 115.15% | 4.78% | 6.61% | 0.74 | -10.40% | nan | -0.14 | 0.065040 |
| BRK-A | 336.52% | 9.40% | 20.73% | 0.54 | -51.47% | nan | 0.65 | 0.048488 |
In [62]:
fig, axes = plt.subplots(len(strategy_returns), 1, figsize=(12, 10), sharex=True)
for ax, (name, series) in zip(axes, strategy_returns.items()):
aligned = series.align(bench_returns, join="inner")[0]
ax.plot(aligned.index, aligned, label=name, color="black", alpha=0.6)
ax.plot(bench_returns.index, bench_returns["SPY"], label="SPY", alpha=0.7)
ax.plot(bench_returns.index, bench_returns["QQQ"], label="QQQ", alpha=0.7)
ax.plot(bench_returns.index, bench_returns["IEF"], label="IEF", alpha=0.7)
ax.plot(bench_returns.index, bench_returns["BRK-A"], label="BRK-A", alpha=0.7)
ax.set_ylabel("Daily Return")
ax.legend(loc="upper right")
ax.grid(True, alpha=0.2)
axes[-1].set_xlabel("Date")
plt.suptitle("Daily Returns: Strategies vs Benchmarks")
plt.tight_layout()
plt.show()
In [ ]:
fig, axes = plt.subplots(len(strategy_returns), 1, figsize=(12, 10), sharex=True)
for ax, (name, series) in zip(axes, strategy_returns.items()):
combined = pd.concat(
[series, bench_returns["SPY"], bench_returns["QQQ"], bench_returns["IEF"], bench_returns["BRK-A"]],
axis=1,
keys=[name, "SPY", "QQQ", "IEF", "BRK-A"]
).dropna()
log_curves = np.log1p(combined).cumsum()
for label in log_curves.columns:
ax.plot(log_curves.index, log_curves[label], label=label, alpha=0.7)
ax.set_ylabel("Log cumulative return")
ax.legend(loc="upper left")
ax.grid(True, alpha=0.2)
axes[-1].set_xlabel("Date")
plt.suptitle("Log Equity Curves: Strategies vs Benchmarks")
plt.tight_layout()
plt.show()